import Interceptor from './core/interceptor';
import Request from './index';
import { refeshToken } from '@/http/login/userLogin.js';
import {
	publicPath
} from '@/plugins/common/env.js';
import store from '@/store/index.js';
export const globalInterceptor = { //全局拦截器
	request: new Interceptor(),
	response: new Interceptor()
};
// 加载防抖
const debounce = function (fn, delay) {
	let timer = null;
	return function () {
		let arg = arguments;
		clearTimeout(timer);
		timer = setTimeout(() => {
			fn.apply(this, arg);
		}, delay);
	};
};
const hideLoading = debounce(function hideLoading () {
	// 停止加载动画
	uni.hideLoading();
}, 500)
// tab取消loding
const routers = [
	'pages/index/index',
	'pages/user/index'
]
/**
 * 全局配置
 * 只能配置 静态数据
 * `content-type` 默认为 application/json
 * `header` 中`content-type`设置特殊参数 或 配置其他会导致触发 跨域 问题，出现跨域会直接进入响应拦截器的catch函数中
 */
export const config = {
	baseURL: publicPath,
	header: {
		'content-type': 'application/x-www-form-urlencoded;charset=utf-8',
	}
};

/**
 * 全局 请求拦截器, 支持添加多个拦截器
 * 例如: 配置token、添加一些默认的参数
 *
 * `return config` 继续发送请求
 * `return false` 会停止发送请求，不会进入错误数据拦截，也不会进入请求对象中的catch函数中
 * `return Promise.reject('xxxxx')` 停止发送请求, 会错误数据拦截，也会进入catch函数中
 *
 * @param {Object} config 发送请求的配置数据
 */
globalInterceptor.request.use(
	(config) => {
		//全局拦截器
		if (config.meta.isToken) {
			//请求是否需要携带token
			getToken() && (config.header.Authorization = getToken().accesstoken);
		}
		//请求是否需要Json
		if (config.meta.isJson) {
			config.header = {
				...config.header,
				'content-type': 'application/json;charset=utf-8',
			}
		}
		// 除了routers 页面的接口全部loading
		const router = getCurrentPages()[getCurrentPages().length - 1]?.route ?? '';
		if (!routers.includes(router)) {
			uni.showLoading({
				title: `加载中...`,
				mask: true
			});
		}

		return config;
	},
	(err) => {
		console.error('is global fail request interceptor: ', err);
		return false;
	}
);

/**
 * 全局 响应拦截器, 支持添加多个拦截器
 * 例如: 根据状态码选择性拦截、过滤转换数据
 *
 * `return res` 继续返回数据
 * `return false` 停止返回数据，不会进入错误数据拦截，也不会进入catch函数中
 * `return Promise.reject('xxxxx')` 返回错误信息, 会错误数据拦截，也会进入catch函数中
 *
 * @param {Object} res 请求返回的数据
 * @param {Object} config 发送请求的配置数据
 * @return {Object|Boolean|Promise<reject>}
 */
globalInterceptor.response.use(
	async (res, config) => {
		// 停止加载动画
		hideLoading()
		// 跳过 `request().download()` 这个拦截
		if (typeof res.tempFilePath !== 'undefined') {
			return res;
		}
		if (config.instanceURL == '/mall-cloud-system/authService/logout') {
			return res;
		} else if (config.instanceURL == '/mall-cloud-system/authService/getImageVerification') {
			return res;
		} else {
			const {
				data,
				data: {
					code
				}
			} = res;
			try {
				return await handleCode({
					data,
					code,
					config
				});
			} catch (err) {
				return Promise.reject(res);
			}
		}
	},
	(err, config) => {
		// 停止加载动画
		hideLoading()
		// 这里判断状态为请求失败
		if (err.data.message) {
			showToast(err.data.message);
		} else {
			console.error('err: ', err);
		}
		return Promise.reject(err);
	}
);

/**
 * 重新请求更新获取 `token`
 * @param {number} uid
 * @return {Promise}
 */
// function getApiToken (rtoken) {
// 	return refeshToken(rtoken)
// }

/**
 * 获取 `localStorage` 中的 `token`
 * @return {string} token字符串
 */
function getToken () {
	return uni.getStorageSync('token');
}

/**
 * 保存 `token` 到  `localStorage`
 * @param {string} token token字符串
 * @return {void}
 */
function saveToken (token) {
	uni.setStorageSync("token", {
		accesstoken: token.a_token,
		refeshtoken: token.r_token
	})
}

/**
 * 处理 http状态码
 * @param {object} o
 * @param {object} o.data 请求返回的数据
 * @param {object} o.config 本次请求的config数据
 * @param {string|number} o.code http状态码
 * @return {object|Promise<reject>}
 */

let isRefreshing = false // 标记是否正在刷新 token 避免重新请求
let requests = [] // 存储待重发请求的数组
function handleCode ({
	data,
	code,
	config
}) {
	const STATUS = {
		'200' () {
			return data;
		},
		'202' () {
			return data;
		},
		'400' () {
			return Promise.resolve(data);
		},
		'401' () {
			// 只让这个实例发送一次请求，如果code还是401则抛出错误
			if (data.message == 'token无效') {
				// 加此判断因  其他接口也会返回401的状态，特此设置
				config.url = config.instanceURL; // 重置 config的相对地址，避免 `params` 多次添加
				let rtoken = getToken().refeshtoken;
				let errconfig = config;
				if (!isRefreshing) {
					isRefreshing = true
					return refeshToken(rtoken).then((res) => {
						if (res.code == 200) {
							saveToken(res.data)
							requests.forEach((cb) => cb(rtoken));
							requests = [] // 重新请求完清空
							return Request.request(config)
						} else {
							store.commit('REMOVE_LOGIN')
							uni.switchTab({
								url: '/pages/user/index'
							})
						}
					}).catch((erro) => {
						store.commit('REMOVE_LOGIN')
						uni.switchTab({
							url: '/pages/user/index'
						})
					})
						.finally(() => {
							// 设置请求是否成功设置为false
							isRefreshing = false
						})
				} else {
					// 返回未执行 resolve 的 Promise
					return new Promise(resolve => {
						// 用函数形式将 resolve 存入，等待刷新后再执行
						requests.push(() => {
							resolve(Request.request(config))
						})
					})
				}
			} else {
				return Promise.reject(data);
			}
		},
		'403' () {
			return Promise.reject({
				code,
				msg: '拒绝请求'
			});
		},
		'500' () {
			data.msg = data.message;//页面中多处使用了code为500时的字段msg。
			return data;
		}
	};
	// 处理列表接口
	return errorLogMessage(data, code, config, STATUS)
}

// 显示消息提示框
function showToast (data) {
	uni.showToast({
		title: data,
		icon: 'none',
		duration: 5000
	});
}

function errorLogMessage (data, code, config, STATUS) {
	return STATUS[code] ? STATUS[code]() : Promise.reject(data, config); // 有状态码但不在这个封装的配置里，就直接进入 `fail`
}

